package com.crm.business.crm.service.impl;

import com.crm.business.admin.service.AdminService;
import com.crm.business.crm.mapper.CrmRoiYearStatisMapper;
import com.crm.business.crm.service.*;
import com.crm.business.servlet.BaseServiceImpl;
import com.crm.common.crm.constant.CrmEnum;
import com.crm.common.crm.entity.BO.CrmRoiPutinPageBO;
import com.crm.common.crm.entity.PO.CrmRoiYearStatis;
import com.crm.common.crm.entity.VO.CrmLeadsRoiStatisVO;
import com.crm.common.crm.entity.VO.CrmModelFiledVO;
import com.crm.common.crm.entity.VO.CrmRoiStatisVO;
import com.crm.common.utils.DateUtils;
import com.crm.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;


/**
 * <p>
 * 投放消耗表 服务实现类
 * </p>
 *
 * @author zhangzhiwei
 * @since 2020-05-21
 */
@Service
@Slf4j
public class CrmRoiYearStatisServiceImpl extends BaseServiceImpl<CrmRoiYearStatisMapper, CrmRoiYearStatis> implements ICrmRoiYearStatisService, CrmPageService {

    @Qualifier("roiStatisExecutor")
    @Autowired
    private Executor statisYearRoiExecutor;

    @Autowired
    private ICrmReceivablesService crmReceivablesService;

    @Autowired
    private ICrmLeadsService crmLeadsService;


    @Autowired
    private AdminService adminService;

    @Autowired
    private ICrmReFundService crmReFundService;

    @Autowired
    private ICrmPutinMoneyService crmPutinMoneyService;

    @Autowired
    private ICrmRoiPutinService crmRoiPutinService;

    @Override
    public String[] appendSearch() {
        return new String[0];
    }

    @Override
    public void setOtherField(Map<String, Object> map) {

    }

    @Override
    public CrmEnum getLabel() {
        return null;
    }

    @Override
    public List<CrmModelFiledVO> queryDefaultField() {
        return null;
    }


    public void statisYearRoi(){
        statisYearRoiExecutor.execute(() -> {
            String startTime = DateUtils.getTime();
            SpringUtils.getBean(ICrmRoiYearStatisService.class).roiYearStatis();
            SpringUtils.getBean(ICrmRoiYearStatisService.class).roiYearStatisForSource();
            String endTime = DateUtils.getTime();
            log.info("startTime:{},endTime:{}",startTime,endTime);
        });
    }

    public void roiYearStatis(){
        // 实际ROI(每日ROI总和/天数)(近3个月)(20231018-近一年)
        LocalDate today = LocalDate.now();
        LocalDate yearsAgo = today.minus(1, ChronoUnit.YEARS);
        yearsAgo = yearsAgo.minus(1, ChronoUnit.DAYS);

        LocalDate yesterday = LocalDate.now();
        LocalDate yesterdayAgo = yesterday.minus(1, ChronoUnit.DAYS);

        CrmRoiPutinPageBO roiPutinPageBO = new CrmRoiPutinPageBO();
        roiPutinPageBO.setStartPutinFormDate(DateUtils.toDate(yearsAgo));
        roiPutinPageBO.setEndPutinFormDate(DateUtils.toDate(yesterdayAgo));
        // 消耗
        List<CrmRoiStatisVO> putinStatisByFormDate = crmRoiPutinService.queryPutinStatisByFormDate(roiPutinPageBO);
        Map<String, BigDecimal> putinStatis = putinStatisByFormDate.stream().collect(Collectors.toMap(CrmRoiStatisVO::getPutinFormDate, CrmRoiStatisVO::getPutinMoney));

        // 表单量
        List<CrmLeadsRoiStatisVO> crmLeadsRoiStatisVOS = crmLeadsService.queryLeadsStatisForData(null, String.valueOf(yearsAgo) + " 00:00:00", String.valueOf(yesterdayAgo) + " 00:00:00",null);
        Map<String, Integer> crmLeadsRoiStatis = crmLeadsRoiStatisVOS.stream().collect(Collectors.toMap(CrmLeadsRoiStatisVO::getLeadsCreateTime, CrmLeadsRoiStatisVO::getLeadsCount));
        // 回款金额
        List<CrmRoiStatisVO> receivablesStatisByFormDate = crmReceivablesService.queryPutinStatisByFormDate(roiPutinPageBO);
        Map<String, BigDecimal> receivablesStatis = receivablesStatisByFormDate.stream().collect(Collectors.toMap(CrmRoiStatisVO::getLeadsFormTime, CrmRoiStatisVO::getReceivablesMoney));
        // 预期回款金额
        List<CrmRoiStatisVO> expectReceivablesStatisByFormDate = crmReceivablesService.queryExpectPutinStatisByFormDate(roiPutinPageBO);
        Map<String, BigDecimal> expectReceivablesStatis = expectReceivablesStatisByFormDate.stream().collect(Collectors.toMap(CrmRoiStatisVO::getLeadsFormTime, CrmRoiStatisVO::getExpectReceivablesMoney));

        while (!yearsAgo.isAfter(yesterdayAgo)) {
            // 消耗
            BigDecimal putinMoney = putinStatis.get(String.valueOf(yearsAgo));
            if (putinMoney == null) {
                putinMoney = new BigDecimal(0.00);
            }

            // 表单量
            Integer leadsNum = crmLeadsRoiStatis.get(String.valueOf(yearsAgo) + " 00:00:00");
            // 回款金额
            BigDecimal receivablesMoney = receivablesStatis.get(String.valueOf(yearsAgo) + " 00:00:00");
            // 预期回款金额
            BigDecimal expectReceivablesMoney = expectReceivablesStatis.get(String.valueOf(yearsAgo) + " 00:00:00");

            // 实际ROI
            BigDecimal realityRoi = new BigDecimal(0.00);
            if(receivablesMoney != null && receivablesMoney.compareTo(new BigDecimal(0.00)) > 0 && putinMoney.compareTo(new BigDecimal(0.00)) > 0){
                realityRoi = receivablesMoney.divide(putinMoney, 2, RoundingMode.HALF_UP);
            }
            // 实际客单价
            BigDecimal realityPrice = new BigDecimal(0.00);
            if(leadsNum != null && leadsNum != 0){
                realityPrice = putinMoney.divide(new BigDecimal(leadsNum), 2, RoundingMode.HALF_UP);
            }

            CrmRoiYearStatis oldYearStatis = baseMapper.queryYearStatisForFormDate(String.valueOf(yearsAgo));
            if(oldYearStatis != null){
                oldYearStatis.setPutinFormDate(String.valueOf(yearsAgo));
                oldYearStatis.setPutinMoney(putinMoney);
                oldYearStatis.setLeadsNum(leadsNum);
                oldYearStatis.setReceivablesMoney(receivablesMoney);
                oldYearStatis.setExpectReceivablesMoney(expectReceivablesMoney);
                oldYearStatis.setRealityRoi(realityRoi);
                oldYearStatis.setRealityPrice(realityPrice);
                updateById(oldYearStatis);
            }else{
                CrmRoiYearStatis yearStatis = new CrmRoiYearStatis();
                yearStatis.setPutinFormDate(String.valueOf(yearsAgo));
                yearStatis.setPutinMoney(putinMoney);
                yearStatis.setLeadsNum(leadsNum);
                yearStatis.setReceivablesMoney(receivablesMoney);
                yearStatis.setExpectReceivablesMoney(expectReceivablesMoney);
                yearStatis.setRealityRoi(realityRoi);
                yearStatis.setRealityPrice(realityPrice);
                save(yearStatis);
            }

            yearsAgo = yearsAgo.plusDays(1);  // 将日期增加1天
        }
    }

    @Override
    public void roiYearStatisForSource(){

        List<String> sourceList = crmPutinMoneyService.querySource();

        LocalDate today = LocalDate.now();
        LocalDate yearsAgo = today.minus(1, ChronoUnit.YEARS);
        yearsAgo = yearsAgo.minus(1, ChronoUnit.DAYS);

        LocalDate yesterday = LocalDate.now();
        LocalDate yesterdayAgo = yesterday.minus(1, ChronoUnit.DAYS);

        // 消耗金额
        List<CrmRoiStatisVO> crmRoiStatisVOList = crmRoiPutinService.queryPutinStatisForYearsSource(String.valueOf(yearsAgo), String.valueOf(yesterdayAgo));
        Map<String, List<CrmRoiStatisVO>> crmYearRoiMap = crmRoiStatisVOList.stream().collect(Collectors.groupingBy(CrmRoiStatisVO::getPutinPlatform));

        // 表单量
        List<CrmLeadsRoiStatisVO> leadsRoiStatisVOList = crmLeadsService.queryRoiStatis(String.valueOf(yearsAgo), String.valueOf(yesterdayAgo));
        Map<String, List<CrmLeadsRoiStatisVO>> crmLeadsVOMap = leadsRoiStatisVOList.stream().collect(Collectors.groupingBy(CrmLeadsRoiStatisVO::getSource));

        // 回款金额
        List<CrmRoiStatisVO> sourceStatisList = crmReceivablesService.queryRoiStatis(String.valueOf(yearsAgo), String.valueOf(yesterdayAgo));
        Map<String, List<CrmRoiStatisVO>> crmRoiStatisVOMap = sourceStatisList.stream().collect(Collectors.groupingBy(CrmRoiStatisVO::getPutinPlatform));

        // 预期回款金额
        List<CrmRoiStatisVO> sourceExpectStatisList = crmReceivablesService.queryExpectRoiStatis(String.valueOf(yearsAgo), String.valueOf(yesterdayAgo));
        Map<String, List<CrmRoiStatisVO>> crmRoiExpectStatisVOMap = sourceExpectStatisList.stream().collect(Collectors.groupingBy(CrmRoiStatisVO::getPutinPlatform));

        while (!yearsAgo.isAfter(yesterdayAgo)) {
            for(String source : sourceList){
                // 消耗金额
                List<CrmRoiStatisVO> crmRoiStatisVOS = crmYearRoiMap.get(source);
                BigDecimal putinMoney = new BigDecimal("0.00");
                if(!CollectionUtils.isEmpty(crmRoiStatisVOS)){
                    Map<String, BigDecimal> collect = crmRoiStatisVOS.stream().collect(Collectors.toMap(CrmRoiStatisVO::getPutinFormDate, CrmRoiStatisVO::getPutinMoney));
                    putinMoney = collect.get(String.valueOf(yearsAgo));
                }

                // 表单量
                List<CrmLeadsRoiStatisVO> crmLeadsStatisList = crmLeadsVOMap.get(source);
                Integer leadsCount = 0;
                if(!CollectionUtils.isEmpty(crmLeadsStatisList)){
                    Map<String, Integer> collect = crmLeadsStatisList.stream().collect(Collectors.toMap(CrmLeadsRoiStatisVO::getLeadsCreateTime, CrmLeadsRoiStatisVO::getLeadsCount));
                    leadsCount = collect.get(String.valueOf(yearsAgo) + " 00:00:00");
                }

                // 回款金额
                List<CrmRoiStatisVO> crmReceivablesStatisList = crmRoiStatisVOMap.get(source);
                BigDecimal receivablesMoney = new BigDecimal("0.00");
                if(!CollectionUtils.isEmpty(crmReceivablesStatisList)){
                    Map<String, BigDecimal> collect = crmReceivablesStatisList.stream().collect(Collectors.toMap(CrmRoiStatisVO::getLeadsFormTime, CrmRoiStatisVO::getReceivablesMoney));
                    receivablesMoney = collect.get(String.valueOf(yearsAgo) + " 00:00:00");
                }

                // 预期回款金额
                List<CrmRoiStatisVO> crmExpectReceivablesStatisList = crmRoiExpectStatisVOMap.get(source);
                BigDecimal expectReceivablesMoney = new BigDecimal("0.00");
                if(!CollectionUtils.isEmpty(crmExpectReceivablesStatisList)){
                    Map<String, BigDecimal> collect = crmExpectReceivablesStatisList.stream().collect(Collectors.toMap(CrmRoiStatisVO::getLeadsFormTime, CrmRoiStatisVO::getExpectReceivablesMoney));
                    expectReceivablesMoney = collect.get(String.valueOf(yearsAgo) + " 00:00:00");
                }

                // 实际ROI
                BigDecimal realityRoi = new BigDecimal("0.00");
                boolean receivablesMoneyResult = null != receivablesMoney && receivablesMoney.compareTo(new BigDecimal(0.00)) > 0;
                boolean putinMoneyResult = null != putinMoney && putinMoney.compareTo(new BigDecimal(0.00)) > 0;
                if(putinMoneyResult && receivablesMoneyResult){
                    realityRoi = receivablesMoney.divide(putinMoney, 2, RoundingMode.HALF_UP);
                }
                // 实际客单价
                BigDecimal realityPrice = new BigDecimal("0.00");
                if(putinMoneyResult && (leadsCount != null && leadsCount != 0)){
                    realityPrice = putinMoney.divide(new BigDecimal(leadsCount), 2, RoundingMode.HALF_UP);
                }

                boolean putinMoneyBool = false;
                boolean leadsCountBool = false;
                boolean receivablesMoneyBool = false;
                boolean expectReceivablesMoneyBool = false;
                if(null != putinMoney && putinMoney.compareTo(new BigDecimal(0.00)) > 0){
                    putinMoneyBool = true;
                }
                if(leadsCount != null && leadsCount != 0){
                    leadsCountBool = true;
                }
                if(null != receivablesMoney && receivablesMoney.compareTo(new BigDecimal(0.00)) > 0){
                    receivablesMoneyBool = true;
                }
                if(null != expectReceivablesMoney && expectReceivablesMoney.compareTo(new BigDecimal(0.00)) > 0){
                    expectReceivablesMoneyBool = true;
                }

                if(!(putinMoneyBool || leadsCountBool || receivablesMoneyBool || expectReceivablesMoneyBool)){
                    continue;
                }

                CrmRoiYearStatis oldYearStatis = baseMapper.queryYearStatisForData(String.valueOf(yearsAgo), source);
                if(oldYearStatis != null){
                    oldYearStatis.setPutinFormDate(String.valueOf(yearsAgo));
                    oldYearStatis.setPutinMoney(putinMoney);
                    oldYearStatis.setLeadsNum(leadsCount);
                    oldYearStatis.setReceivablesMoney(receivablesMoney);
                    oldYearStatis.setExpectReceivablesMoney(expectReceivablesMoney);
                    oldYearStatis.setRealityRoi(realityRoi);
                    oldYearStatis.setRealityPrice(realityPrice);
                    updateById(oldYearStatis);
                }else{
                    CrmRoiYearStatis yearStatis = new CrmRoiYearStatis();
                    yearStatis.setPutinPlatform(source);
                    yearStatis.setPutinMoney(putinMoney);
                    yearStatis.setPutinFormDate(String.valueOf(yearsAgo));
                    yearStatis.setLeadsNum(leadsCount);
                    yearStatis.setReceivablesMoney(receivablesMoney);
                    yearStatis.setExpectReceivablesMoney(expectReceivablesMoney);
                    yearStatis.setRealityRoi(realityRoi);
                    yearStatis.setRealityPrice(realityPrice);
                    save(yearStatis);
                }
            }
            yearsAgo = yearsAgo.plusDays(1);  // 将日期增加1天
        }
    }

    public static void main(String[] args) {
        String startDateStr = "2022-10-01";
        String endDateStr = "2023-09-30";

        LocalDate startDate = LocalDate.parse(startDateStr);
        LocalDate endDate = LocalDate.parse(endDateStr);

        YearMonth startYearMonth = YearMonth.from(startDate);
        int startYear = startYearMonth.getYear();
        int startMonth = startYearMonth.getMonthValue();

        for (int year = startYear; year <= endDate.getYear(); year++) {
            int monthStart = (year == startYear) ? startMonth : 1;
            int monthEnd = (year == endDate.getYear()) ? endDate.getMonthValue() : 12;

            for (int month = monthStart; month <= monthEnd; month++) {
                YearMonth yearMonth = YearMonth.of(year, month);
                System.out.println(year + "-" + (yearMonth.getMonthValue() < 10 ? "0" + yearMonth.getMonthValue() : yearMonth.getMonthValue()));
            }
        }
    }

    /**
     * ROI年度统计
     * @param source
     * @return
     */
    @Override
    public Map<String,Object> roiStatisForYear(String source){
        LocalDate today = LocalDate.now();
        // 去年当前月第一天
        LocalDate yearsAgo = today.minusYears(1);
        LocalDate yearsBeforeFirst = yearsAgo.with(TemporalAdjusters.firstDayOfMonth());
        // 上个月最后一天
        LocalDate monthAgo = today.minusMonths(1);
        LocalDate monthBeforeLast = monthAgo.with(TemporalAdjusters.lastDayOfMonth());
        List<CrmRoiYearStatis> yearStatisList = baseMapper.queryYearStatis(source,String.valueOf(yearsBeforeFirst), String.valueOf(monthBeforeLast));

        Map<String, CrmRoiYearStatis> yearStatisMap = yearStatisList.stream().collect(Collectors.toMap(CrmRoiYearStatis::getPutinFormDate, v -> v, (p1, p2) -> p1));

        YearMonth startYearMonth = YearMonth.from(yearsBeforeFirst);
        int startYear = startYearMonth.getYear();
        int startMonth = startYearMonth.getMonthValue();

        List<String> yearMonthList = new ArrayList<>();
        List<BigDecimal> averageRoiList = new ArrayList<>();
        List<BigDecimal> realityRoiList = new ArrayList<>();
        List<BigDecimal> expectRoiList = new ArrayList<>();

        for (int year = startYear; year <= monthBeforeLast.getYear(); year++) {
            int monthStart = (year == startYear) ? startMonth : 1;
            int monthEnd = (year == monthBeforeLast.getYear()) ? monthBeforeLast.getMonthValue() : 12;

            for (int month = monthStart; month <= monthEnd; month++) {
                YearMonth yearMonth = YearMonth.of(year, month);
                int dayNum = yearMonth.lengthOfMonth();
                String yearAndMonth = year + "-" + (yearMonth.getMonthValue() < 10 ? "0" + yearMonth.getMonthValue() : yearMonth.getMonthValue());

                yearMonthList.add(yearAndMonth);

                CrmRoiYearStatis yearStatis = yearStatisMap.get(yearAndMonth);
                if(yearStatis != null){
                    if(yearStatis.getPutinMoney() != null && yearStatis.getPutinMoney().compareTo(new BigDecimal(0.00)) > 0){
                        // 平均ROI
                        if(yearStatis.getReceivablesMoney() != null && yearStatis.getReceivablesMoney().compareTo(new BigDecimal(0.00)) > 0){
                            BigDecimal averageRoi = yearStatis.getReceivablesMoney().divide(yearStatis.getPutinMoney(), 2, RoundingMode.HALF_UP);
                            averageRoiList.add(averageRoi);
                        }
                        // 实际ROI
                        if(yearStatis.getRealityRoi() != null && dayNum != 0){
                            BigDecimal realityRoi = yearStatis.getRealityRoi().divide(new BigDecimal(dayNum), 2, RoundingMode.HALF_UP);
                            realityRoiList.add(realityRoi);
                        }
                        // 预期ROI
                        if(yearStatis.getExpectReceivablesMoney() != null && yearStatis.getExpectReceivablesMoney().compareTo(new BigDecimal(0.00)) > 0){
                            BigDecimal expectRoi = yearStatis.getExpectReceivablesMoney().divide(yearStatis.getPutinMoney(), 2, RoundingMode.HALF_UP);
                            expectRoiList.add(expectRoi);
                        }
                    }else{
                        averageRoiList.add(new BigDecimal("0.00"));
                        realityRoiList.add(new BigDecimal("0.00"));
                        expectRoiList.add(new BigDecimal("0.00"));
                    }
                }else{
                    averageRoiList.add(new BigDecimal("0.00"));
                    realityRoiList.add(new BigDecimal("0.00"));
                    expectRoiList.add(new BigDecimal("0.00"));
                }
            }
        }

        Map<String,Object> returnMap = new HashMap<>();
        returnMap.put("yearMonthList",yearMonthList);
        returnMap.put("averageRoiList",averageRoiList);
        returnMap.put("realityRoiList",realityRoiList);
        returnMap.put("expectRoiList",expectRoiList);

        return returnMap;
    }

    /**
     * 客单价年度统计
     * @param source
     * @return
     */
    @Override
    public Map<String,Object> priceStatisForYear(String source){
        LocalDate today = LocalDate.now();
        // 去年当前月第一天
        LocalDate yearsAgo = today.minusYears(1);
        LocalDate yearsBeforeFirst = yearsAgo.with(TemporalAdjusters.firstDayOfMonth());
        // 上个月最后一天
        LocalDate monthAgo = today.minusMonths(1);
        LocalDate monthBeforeLast = monthAgo.with(TemporalAdjusters.lastDayOfMonth());
        List<CrmRoiYearStatis> yearStatisList = baseMapper.queryYearStatis(source,String.valueOf(yearsBeforeFirst), String.valueOf(monthBeforeLast));

        Map<String, CrmRoiYearStatis> yearStatisMap = yearStatisList.stream().collect(Collectors.toMap(CrmRoiYearStatis::getPutinFormDate, v -> v, (p1, p2) -> p1));

        YearMonth startYearMonth = YearMonth.from(yearsBeforeFirst);
        int startYear = startYearMonth.getYear();
        int startMonth = startYearMonth.getMonthValue();

        List<String> yearMonthList = new ArrayList<>();
        List<BigDecimal> averagePriceList = new ArrayList<>();
        List<BigDecimal> realityPriceList = new ArrayList<>();

        for (int year = startYear; year <= monthBeforeLast.getYear(); year++) {
            int monthStart = (year == startYear) ? startMonth : 1;
            int monthEnd = (year == monthBeforeLast.getYear()) ? monthBeforeLast.getMonthValue() : 12;

            for (int month = monthStart; month <= monthEnd; month++) {
                YearMonth yearMonth = YearMonth.of(year, month);
                int dayNum = yearMonth.lengthOfMonth();
                String yearAndMonth = year + "-" + (yearMonth.getMonthValue() < 10 ? "0" + yearMonth.getMonthValue() : yearMonth.getMonthValue());

                yearMonthList.add(yearAndMonth);

                CrmRoiYearStatis yearStatis = yearStatisMap.get(yearAndMonth);
                if(yearStatis != null){
                    if(yearStatis.getPutinMoney() != null && yearStatis.getPutinMoney().compareTo(new BigDecimal(0.00)) > 0){
                        // 平均客单价
                        if(yearStatis.getLeadsNum() != null && yearStatis.getLeadsNum() != 0){
                            BigDecimal averageRoi = yearStatis.getPutinMoney().divide(new BigDecimal(yearStatis.getLeadsNum()), 2, RoundingMode.HALF_UP);
                            averagePriceList.add(averageRoi);
                        }
                        // 实际客单价
                        if(yearStatis.getRealityPrice() != null && dayNum != 0){
                            BigDecimal realityRoi = yearStatis.getRealityPrice().divide(new BigDecimal(dayNum), 2, RoundingMode.HALF_UP);
                            realityPriceList.add(realityRoi);
                        }
                    }else{
                        averagePriceList.add(new BigDecimal("0.00"));
                        realityPriceList.add(new BigDecimal("0.00"));
                    }
                }else{
                    averagePriceList.add(new BigDecimal("0.00"));
                    realityPriceList.add(new BigDecimal("0.00"));
                }
            }
        }

        Map<String,Object> returnMap = new HashMap<>();
        returnMap.put("yearMonthList",yearMonthList);
        returnMap.put("averagePriceList",averagePriceList);
        returnMap.put("realityPriceList",realityPriceList);

        return returnMap;
    }
}
